using System;
using CodePlex.DnD4eCampaignManager.DnD4e;
using CodePlex.DnD4eCampaignManager.DnD4e.Interfaces;
using NUnit.Framework;
using Rhino.Mocks;
using StructureMap.AutoMocking;

namespace CodePlex.DnD4eCampaignManager.CampaignManagerTests.DnD4eTests
{
    [TestFixture]
    public class HealingSurgesTests
    {
        private RhinoAutoMocker<HealingSurges> _healingSurgesMocker;

        [Test]
        public void HealingSurgesCurrentCanBeSetWhenHealingSurgesMaximumIsNotSet()
        {
            const int healingSurgesCurrent = 3;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent = healingSurgesCurrent;
            Assert.AreEqual(healingSurgesCurrent, _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent);
        }

        [Test]
        public void HealingSurgesCurrentCannotBeLessThanZero()
        {
            _healingSurgesMocker.ClassUnderTest.HealingSurgesMaximum = 10;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent = -3;
            Assert.AreEqual(0, _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent);
        }

        [Test]
        public void HealingSurgesCurrentCannotExceedHealingSurgesMaximum()
        {
            const int healingSurgesCurrent = 13;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesMaximum = 10;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent = healingSurgesCurrent;
            Assert.AreEqual(_healingSurgesMocker.ClassUnderTest.HealingSurgesMaximum, _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent);
        }

        [Test]
        public void HasHealingSurgesCurrent()
        {
            const int healingSurgesCurrent = 20;
            HealingSurges healingSurges = new HealingSurges(new HitPoints()) { HealingSurgesCurrent = healingSurgesCurrent };
            Assert.AreEqual(healingSurgesCurrent, healingSurges.HealingSurgesCurrent);
        }

        [Test]
        public void HasHealingSurgesMaximum()
        {
            const int healingSurgesMaximum = 20;
            HealingSurges healingSurges = new HealingSurges(new HitPoints()) { HealingSurgesMaximum = healingSurgesMaximum };
            Assert.AreEqual(healingSurgesMaximum, healingSurges.HealingSurgesMaximum);
        }

        [Test]
        public void HasHealingSurgeValue()
        {
            const int healingSurgeValue = 20;
            HealingSurges healingSurges = new HealingSurges(new HitPoints()) { HealingSurgeValue = healingSurgeValue };
            Assert.AreEqual(healingSurgeValue, healingSurges.HealingSurgeValue);
        }

        [Test]
        public void HasFailedDeathSaves()
        {
            const int failedDeathSaves = 2;
            HealingSurges healingSurges = new HealingSurges(new HitPoints()) { FailedDeathSaves = failedDeathSaves };
            Assert.AreEqual(failedDeathSaves, healingSurges.FailedDeathSaves);
        }

        [Test]
        public void ImplementsIEquatable()
        {
            Assert.IsInstanceOfType(typeof ( IEquatable<HealingSurges> ), new HealingSurges(new HitPoints()));
        }

        [Test]
        public void ImplementsIHealingSurges()
        {
            Assert.IsInstanceOfType(typeof ( IHealingSurges ), new HealingSurges(new HitPoints()));
        }

        [Test]
        public void ImplementsIHitPoints()
        {
            Assert.IsInstanceOfType(typeof ( IHitPoints ), new HealingSurges(new HitPoints()));
        }

        [SetUp]
        public void SetUp()
        {
            _healingSurgesMocker = new RhinoAutoMocker<HealingSurges>();
        }

        [Test]
        public void SpendHealingSurgeDoesNotHealHitPointsWhenCurrentHitPointsEqualsMaxHitPoints()
        {
            const int maxHitPoints = 60;
            const int healingSurgesMaximum = 5;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesMaximum = healingSurgesMaximum;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent = healingSurgesMaximum;
            _healingSurgesMocker.Get<IHitPoints>().Expect(hp => hp.HitPointsMaximum).Return(maxHitPoints);
            _healingSurgesMocker.Get<IHitPoints>().Expect(hp => hp.HitPointsCurrent).Return(maxHitPoints);
            _healingSurgesMocker.Get<IHitPoints>().AssertWasNotCalled(hp => hp.Heal(Arg<int>.Is.Anything));

            _healingSurgesMocker.ClassUnderTest.SpendHealingSurge();

            Assert.AreEqual(5, _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent);
        }

        [Test]
        public void SpendHealingSurgeDoesNotHealHitPointsWhenCurrentSurgesIsZero()
        {
            _healingSurgesMocker.ClassUnderTest.HealingSurgesMaximum = 5;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent = 0;
            _healingSurgesMocker.Get<IHitPoints>().AssertWasNotCalled(hp => hp.Heal(Arg<int>.Is.Anything));

            _healingSurgesMocker.ClassUnderTest.SpendHealingSurge();

            Assert.AreEqual(0, _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent);
        }

        [Test]
        public void SpendHealingSurgeHealsOneQuarterOfMaximumHitPoints()
        {
            const int maxHitPoints = 60;
            const int currentHitPoints = maxHitPoints - 10;
            const int healingSurgesMaximum = 5;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesMaximum = healingSurgesMaximum;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent = healingSurgesMaximum;
            _healingSurgesMocker.Get<IHitPoints>().Expect(hp => hp.HitPointsMaximum).Return(maxHitPoints).Repeat.Twice();
            _healingSurgesMocker.Get<IHitPoints>().Expect(hp => hp.HitPointsCurrent).Return(currentHitPoints);
            _healingSurgesMocker.Get<IHitPoints>().Expect(hp => hp.Heal(maxHitPoints / 4));

            _healingSurgesMocker.ClassUnderTest.SpendHealingSurge();
        }

        [Test]
        public void SpendHealingSurgeReducesCurrentSurgesByOneWhenCurrentSurgesIsGreaterThanZero()
        {
            const int healingSurgesStarting = 5;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesMaximum = healingSurgesStarting;
            _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent = healingSurgesStarting;
            _healingSurgesMocker.Get<IHitPoints>().Stub(hp => hp.HitPointsMaximum).Return(50);
            _healingSurgesMocker.Get<IHitPoints>().Stub(hp => hp.HitPointsCurrent).Return(30);

            _healingSurgesMocker.ClassUnderTest.SpendHealingSurge();

            Assert.AreEqual(healingSurgesStarting - 1, _healingSurgesMocker.ClassUnderTest.HealingSurgesCurrent);
        }

        [TearDown]
        public void TearDown()
        {
            _healingSurgesMocker.Get<IHitPoints>().VerifyAllExpectations();
        }
    }
}